package it.okkam.Changes;


import it.okkam.strutturedati.Poligono;
import it.okkam.strutturedati.Punto;
import it.okkam.strutturedati.Vertice;
import it.okkam.utility.ApriStream;
import it.okkam.utility.ConfigReader;
import it.okkam.utility.CoordinateConversion;
import it.okkam.utility.S;
import it.okkam.utility.SGeo;
import it.okkam.utility.S_GS;
import it.okkam.utility.Utility;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Date;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimeZone;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;

import jena.schemagen;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDF;

public class ImportChanges {
	public static void main(String[] args) {	
		Utility ut = new Utility();
		ConfigReader.configReader();
		final long startTime = ut.printInitialTimeSetTime(ConfigReader.cambiamenti);
		
		ImportChanges datiCambiamenti = new ImportChanges();
		System.out.println(ConfigReader.fileCambiamenti);
		List<EventoCambiamento> lista = datiCambiamenti.leggiCambiamenti(ConfigReader.fileCambiamenti);
		/*File cambiamentiFile = */datiCambiamenti.creaFileRDF(ConfigReader.cambiamenti, lista, "TURTLE");
		
		ut.printExecutionTimeChanges(startTime, lista );
		
	}

	public List<EventoCambiamento> leggiCambiamenti(String filePoligoniCambiamentiPath) {

		ArrayList<EventoCambiamento> listaCambiamenti = new ArrayList<EventoCambiamento>();
		ArrayList<String> contenutoFileCambiamenti = null;
		ApriStream apriStream = new ApriStream();

		//lettura file 
		contenutoFileCambiamenti =  apriStream.apriStream(filePoligoniCambiamentiPath); // lettura file Poligoni

		// creazione liste 
		listaCambiamenti = leggiCambiamenti(contenutoFileCambiamenti);

		return listaCambiamenti;	

	}

	private  ArrayList<EventoCambiamento>    leggiCambiamenti(List<String> contenutoFileCambiamenti){
		ArrayList<EventoCambiamento> listaEventiLettura = new ArrayList<EventoCambiamento>();
		Date dataCambiamento= null; 
		Utility ut = new Utility();	
		List<List<Vertice>> listaPuntiPoligono = new ArrayList<List<Vertice>>();
		String tipoCambiamento = null;
		int id=0;
		int indiceOrdine = 0;
		XMLGregorianCalendar newCal = null;
		List<Vertice> puntiPoligono = new ArrayList<Vertice>();
		for(String rigaLetta:contenutoFileCambiamenti)	{

			//gestione data
			if (rigaLetta.startsWith("Data")){
				//caso data
				rigaLetta = rigaLetta.substring(5);
				DateFormat pattern = new SimpleDateFormat("dd/MM/yyyy");
				try {
					Date exampleDateObj = pattern.parse(rigaLetta);
					GregorianCalendar c = new GregorianCalendar();
					c.setTime(exampleDateObj);
					c.get(Calendar.DAY_OF_WEEK);

					newCal= DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
					newCal.setTime(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
					newCal.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
				} catch (ParseException e) {
					e.printStackTrace();
				} catch (DatatypeConfigurationException e) {
					e.printStackTrace();
				}
			}
			else {
				if (rigaLetta.equals("END") ){				
					//fine poligono
					Poligono poligonoLetto = new Poligono();
					Set<Vertice> newPoligono =new HashSet<Vertice>();
					for(Vertice v:puntiPoligono)
						newPoligono.add(v);
					poligonoLetto.setPoligono(newPoligono); // carico i punti del poligono 

					// creo la particella e la popolo
					EventoCambiamento eventoCambiamentoLetto = new EventoCambiamento();
					eventoCambiamentoLetto.setPoligono(poligonoLetto);
					eventoCambiamentoLetto.setTipoCambiamento(tipoCambiamento);
					eventoCambiamentoLetto.setDataCambiamento(newCal);
					eventoCambiamentoLetto.setId(id);

					// carico la particella sulla lista delle particelle lette
					listaEventiLettura.add(eventoCambiamentoLetto);

					// mi preparo a leggere un'altra particella 
					indiceOrdine = 0;
					//listaPuntiPoligono.add(new ArrayList<Vertice>(puntiPoligono));
					puntiPoligono.clear();
				}
				if (rigaLetta.startsWith("n")||rigaLetta.startsWith("e")||rigaLetta.startsWith("A")){
					tipoCambiamento = rigaLetta;
				}
				if (rigaLetta.startsWith("i")){
					id=ut.findId(rigaLetta);
					
				}
				if (rigaLetta.startsWith("0")||rigaLetta.startsWith("1")||rigaLetta.startsWith("2")||rigaLetta.startsWith("3")||
						rigaLetta.startsWith("4")||rigaLetta.startsWith("5")||rigaLetta.startsWith("6")||rigaLetta.startsWith("7")||
						rigaLetta.startsWith("8")||rigaLetta.startsWith("9")){

					Vertice vertice = new Vertice();
					indiceOrdine++;
					vertice = ut.leggiVerticeChangesWGS84(rigaLetta, indiceOrdine);
					puntiPoligono.add(vertice);
				}
			}
		}	return listaEventiLettura;
	}






	public File creaFileRDF(String file, List<EventoCambiamento> listaCambiamenti, String serializzazione) {
		// TODO Auto-generated method stub
		Utility ut = new Utility();
		File fileCambiamentirdf = new File(file);
		Model model = ModelFactory.createDefaultModel();
		String ontologia = "http://www.okkam.it/ont/particella_catastale.owl";
		model.setNsPrefix("pc", "http://www.okkam.it/ont/particella_catastale.owl#"); // set del prefisso

		for(EventoCambiamento eventoCambiamento:listaCambiamenti){

			String poligonoURI = null;
			String puntoURI = null;
			String verticeURI = null;
			String cambiamentoURI = null;
			

			Poligono poligonoLetto = eventoCambiamento.getPoligono();


			//particellaRisorsa.addProperty(Schemagen.haCentro, puntoURI);

			poligonoURI = creaURIPoligono(ontologia, poligonoLetto);
			
			Resource poligonoRisorsa = model.createResource(poligonoURI);
			//System.out.println(eventoCambiamento.getDataCambiamento());
			String data = eventoCambiamento.getDataCambiamento().toXMLFormat();
			//System.out.println(data);
			cambiamentoURI = creaURICambiamento(ontologia, poligonoLetto, data);
			Resource cambiamentoRisorsa = model.createResource(cambiamentoURI);
			//add tipo
			Property pType = model.createProperty(ontologia+"#","Cambiamento");
			cambiamentoRisorsa.addProperty(RDF.type, pType);
			cambiamentoRisorsa.addProperty(S.haID, Integer.toString(eventoCambiamento.getId()));
			cambiamentoRisorsa.addProperty(S.haPoligono, poligonoRisorsa);
			poligonoRisorsa.addProperty(S.poligonoDi, cambiamentoRisorsa);
			cambiamentoRisorsa.addProperty(S.haDataAcquisizione, data);
			cambiamentoRisorsa.addProperty(S.haTipoCambiamento, eventoCambiamento.getTipoCambiamento());//?

			Set<Vertice> listaVertici = poligonoLetto.getPoligono();

			for (Vertice verticeLetto: listaVertici){

				int ordine = verticeLetto.getCardinalita();			

				Punto puntoLetto = verticeLetto.getVertice();
				puntoURI = ut.creaURIPunto(ontologia, puntoLetto);
				verticeURI = ut.creaURIVerticeChanges(poligonoURI, puntoURI, ontologia, Integer.toString(ordine));

				Resource verticeRisorsa = model.createResource(verticeURI);	
				
				//add tipo
				Property pTypeVertice = model.createProperty(ontologia+"#","Vertice");
				verticeRisorsa.addProperty(RDF.type, pTypeVertice);
				
				Resource puntoRisorsa = model.createResource(puntoURI);
				
				//add tipo
				Property pTypePunto = model.createProperty(ontologia+"#","Point");
				puntoRisorsa.addProperty(RDF.type, pTypePunto);
				
				puntoRisorsa.addProperty(SGeo.lat,  model.createTypedLiteral(puntoLetto.getX()));
				puntoRisorsa.addProperty(SGeo.long_,  model.createTypedLiteral(puntoLetto.getY()));
				verticeRisorsa.addProperty(S.haPunto, puntoRisorsa);
				puntoRisorsa.addProperty(S.puntoDi, verticeRisorsa);
				verticeRisorsa.addProperty(S.haNumeroOrdine, Integer.toString(ordine));
				//verticeRisorsa.addLiteral(Schemagen.haNumeroOrdine, Integer.toString(ordine));
				poligonoRisorsa.addProperty(S.haVertice, verticeRisorsa);
				verticeRisorsa.addProperty(S.verticeDi, poligonoRisorsa);

			}

		}

		try{
			model.write(new PrintWriter(fileCambiamentirdf), serializzazione);
		}
		catch(FileNotFoundException e) {			
			e.printStackTrace();
		}
		DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
		Date date = new Date();
		System.out.println("["+dateFormat.format(date)+"] Creazione file " + fileCambiamentirdf.getName() +" terminata!");
		//System.out.println("Il file " + fileLavisrdf.getName() + " "+ fileLavisrdf.length());
		return fileCambiamentirdf;
	}

	



	private String creaURICambiamento (String URIontologia , Poligono poligonoLetto , String data){
		String URIcambiamento = null;

		URIcambiamento = creaURIPoligono(URIontologia, poligonoLetto) + data ;

		return URIcambiamento;

	}

	private String creaURIPoligono(String ontologia, Poligono poligonoLetto){
		String URIpoligono = null; 
		ontologia = ontologia;
		Utility ut = new Utility();
		Set<Vertice> setVertici = poligonoLetto.getPoligono();
		List<Vertice> listaVertici = new ArrayList<Vertice>(setVertici);
		Vertice primoVertice = listaVertici.get(0);
		Vertice secondoVertice = listaVertici.get(1);
		Punto primoPunto = primoVertice.getVertice();
		Punto secondoPunto = secondoVertice.getVertice();

		URIpoligono = ontologia + "/poligono/lat/" + ut.getParteIntera(primoPunto.getX()) + "/" + ut.getParteFrazionaria(primoPunto.getX()) + "/lon/" + ut.getParteIntera(primoPunto.getY()) + "/" +ut.getParteFrazionaria(primoPunto.getY()) + "/wgs84/";
		URIpoligono = URIpoligono + "lat/" + ut.getParteIntera(secondoPunto.getX()) + "/" + ut.getParteFrazionaria(secondoPunto.getX()) + "/lon/" + ut.getParteIntera(secondoPunto.getY()) + "/" +ut.getParteFrazionaria(secondoPunto.getY()) + "/wgs84/";
		return URIpoligono;
	}	
}
